--[[-------------------------------------------------------------------------------
  Copyright (c) 2008, Naitaeti (Bronzebeard EU, Horde)

  Some ideas and code lifted from RS_ClassColors by Stupid (Crushridge US, Horde)
---------------------------------------------------------------------------------]]


--[[-------------------------------------------------------------------------------
	Configuration

  storeClassMeta needs to be enabled for colorizeClass and colorizeLevel to work
  colorizeBG works independently of storeClassMeta
---------------------------------------------------------------------------------]]

-- store class name and level information about each character
local storeClassMeta = true

-- colorize character names in the chat frames
local colorizeClass = true

-- display and colorize level information in the chat frames
local colorizeLevel = false

-- colorize character names in the battleground score frame
local colorizeBG = true

-- left name delimiter, e.g. "<" gives "<Character"
local nameDelimLeft = ""

-- right name delimiter, e.g. ">" gives "Character>"
local nameDelimRight = ""

-- level delimiter, e.g. ":" gives "70:Character"
local levelDelim = ":"

--[[-------------------------------------------------------------------------------
	Code
---------------------------------------------------------------------------------]]

if not LibStub then error("naiColorize requires LibStub.") end
local BC = LibStub("LibBabble-Class-3.0"):GetReverseLookupTable()
if not BC then error("naiColorize requires Babble-Class-3.0.") end

local _AddMessage = ChatFrame1.AddMessage

local blacklist = {
	[ChatFrame2] = true,
--	[ChatFrame4] = true,
}

local playerinfo = { }

local storePlayerInfo = function(name, cls, lvl)
	if class ~= "Unknown" and name ~= nil and playerinfo[name] == nil then
		local info = { class = cls, level = lvl }
		playerinfo[name] = info
	end
end

local getPlayerInfo = function(player)
	if not player then
		return nil
	end

	if playerinfo[player] then
		return playerinfo[player]
	end
	
	-- Check raid
	if (UnitInRaid("player")) then
		for i=1,MAX_RAID_MEMBERS do
			local name, _, subgroup, level,_, class = GetRaidRosterInfo(i)
			if (name and subgroup and class) then
				storePlayerInfo(name, class, level)
			end
		end

		if playerinfo[player] then
			return playerinfo[player]
		end
	end
	
	-- Check party
	if (UnitInParty("player")) then
		for i=1,5 do
			if (UnitName("party" .. i)) then
				storePlayerInfo(UnitName("party" .. i), select(2, UnitClass("party" .. i)), UnitLevel("party" .. i))
			end
		end

		if playerinfo[player] then
			return playerinfo[player]
		end
	end
	
	-- Check friends list
	for i=1,GetNumFriends() do
		local name, level, class = GetFriendInfo(i)
		storePlayerInfo(name, class, level)
	end
	if playerinfo[player] then
		return playerinfo[player]
	end
	
	-- Check the guild
	if (IsInGuild()) then
		local prevRosterSetting = GetGuildRosterShowOffline()
		SetGuildRosterShowOffline(true)
		if (GetNumGuildMembers() == 0) then GuildRoster() end
		for i=1,GetNumGuildMembers() do
			local name, _,_, level, class = GetGuildRosterInfo(i)
			if level ~= nil and level > 0 then
				storePlayerInfo(name, class, level)
			end
		end
		SetGuildRosterShowOffline(prevRosterSetting)

		if playerinfo[player] then
			return playerinfo[player]
		end
	end

	-- Check the player
	if player == UnitName("player") then
		storePlayerInfo(UnitName("player"), select(2, UnitClass("player")), UnitLevel("player"))
		if playerinfo[player] then
			return playerinfo[player]
		end
	end
	
	return nil
end

-- propercase, taken from ZOMGBuffs
local propercase = function(str)
	return str and (strupper(strsub(str, 1, 1))..strlower(strsub(str, 2)))
end

local getColoredName = function(name, class)
	local properclass
	if class then
		properclass = strupper(BC[propercase(class)] or class)
		-- _AddMessage(ChatFrame1, format("color %s %s %s", class, propcls, properclass))
	end
	local r, b, g = 0.63, 0.63, 0.63
	if properclass and RAID_CLASS_COLORS and RAID_CLASS_COLORS[properclass] then
		r, g, b = RAID_CLASS_COLORS[properclass].r, RAID_CLASS_COLORS[properclass].g, RAID_CLASS_COLORS[properclass].b
	end
  
	local _, _, rname, realm = name:find("([^-]+)-([^-]+)")
	if name and realm then
		return string.format("|cFF%02x%02x%02x%s|r-|cFFA1A1A1%s|r", r * 255, g * 255, b * 255, rname, realm)
	end
	return string.format("|cFF%02x%02x%02x%s|r", r * 255, g * 255, b * 255, name)
end

local getColoredLevel = function(level)
	local levelDiff = level - UnitLevel("player")
	local red = 0.0
	local green = 0.0
	local blue = 0.0
	if (levelDiff > 5 or level == -1) then
		red = 1.0
	elseif (levelDiff >= 3) then
		red = 1.0
		green = 0.5
	elseif (levelDiff >= -2) then
		red = 1.0
		green = 1.0
	elseif (-levelDiff <= GetQuestGreenRange()) then
		green = 1.0
	else
		red = 0.5
		green = 0.5
		blue = 0.5
	end
	return string.format("|cFF%02x%02x%02x%d|r", red * 255, green * 255, blue * 255, level)
end

local AddMessage = function(self, text, ...)
	if(type(text) == "string") then
		if text == "" then
			return _AddMessage(self, text, ...)
		end

		local info = nil
		local _, _, playername = text:find("|Hplayer:[^:]+:%d+|h%[(.-)%]|h")
		if playername then
			if storeClassMeta then
				info = getPlayerInfo(playername)
			end
			
			if colorizeClass or colorizeLevel then
				local ccolor, lcolor = playername, ""
				if colorizeClass then
					if info ~= nil then
						ccolor = getColoredName(playername, info.class)
					else
						ccolor = getColoredName(playername, nil)
					end
				end
				if colorizeLevel and info ~= nil then
					lcolor = getColoredLevel(info.level)..levelDelim
				end
				text = text:gsub("|Hplayer:([^:]+):(%d+)|h%[.-%]|h", 
												 "|Hplayer:%1:%2|h"..nameDelimLeft..lcolor..ccolor..nameDelimRight.."|h")
			end
		end
	end

	return _AddMessage(self, text, ...)
end

for i=1, NUM_CHAT_WINDOWS do
	local cf = _G["ChatFrame"..i]
	if(not blacklist[cf]) then
		cf.AddMessage = AddMessage
	end
end

if colorizeBG then
	hooksecurefunc("WorldStateScoreFrame_Update", function()
		for i=1,MAX_WORLDSTATE_SCORE_BUTTONS do
			local index = FauxScrollFrame_GetOffset(WorldStateScoreScrollFrame) + i
			if index > GetNumBattlefieldScores() then break end
			local _,_,_,_,_,_,_,_, class = GetBattlefieldScore(index)
			local nameText = getglobal("WorldStateScoreButton" .. i .. "NameText"):GetText()
			if (nameText == UnitName("player")) then
				getglobal("WorldStateScoreButton" .. i .. "NameText"):SetText("|cff00ff00" .. nameText .. "|r")
			else
				getglobal("WorldStateScoreButton" .. i .. "NameText"):SetText(getColoredName(nameText, class))
			end
		end
	end)
end

local frame = CreateFrame("Frame", nil, UIParent)

frame:RegisterEvent("UPDATE_MOUSEOVER_UNIT")
frame:RegisterEvent("WHO_LIST_UPDATE")

frame:SetScript("OnEvent", function ()
	if storeClassMeta then
		if event == "UPDATE_MOUSEOVER_UNIT" then
			if UnitExists("mouseover") and UnitIsPlayer("mouseover") and UnitIsFriend("player", "mouseover") then
				storePlayerInfo(UnitName("mouseover"), select(2, UnitClass("mouseover")), UnitLevel("mouseover"))
			end
		elseif event == "WHO_LIST_UPDATE" then
			local _, numWhos = GetNumWhoResults()
			for i=1,numWhos do
				local name, _, level, _, class = GetWhoInfo(i)
				storePlayerInfo(name, class, level)
			end
		end
	end
end)
